Skip to content

chore(capsule): #470 诊断 v2 — 暗点一次性日志(零行为改动)#593

Merged
H-Chris233 merged 1 commit into
betafrom
chore/issue-470-capsule-diagnostics-v2
Jun 4, 2026
Merged

chore(capsule): #470 诊断 v2 — 暗点一次性日志(零行为改动)#593
H-Chris233 merged 1 commit into
betafrom
chore/issue-470-capsule-diagnostics-v2

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented Jun 4, 2026

User description

refs #470不 close:这是诊断手段,不是修复)

背景

#470「Windows 语音输入看不到录音胶囊」根因至今未定:PR #471 已白纸黑字说明「只加诊断 log、不是真修复、需要真机日志」;byte92 报告 macOS 也复现,疑为跨平台共性。任何不基于真机日志的「修复」极可能修错对象,因此本 PR 不改任何 show/hide/position 行为,只在几个静默路径补日志,把根因收敛到单一分支:

  • A:后端没 emit / 状态机停在 Idle(两条既有 [capsule] 日志 + 前端是否收到事件)
  • Bshow_capsule 开关被关(既有 suppressed by user toggle 日志)
  • C:Win32 show 跑了但 topmost 被拦 / 定位到屏幕外
  • A0:capsule webview 窗口压根没创建/已销毁

改动(纯增量 log,零行为)

位置 此前 现在
coordinator.rs show_capsule_window_no_activate(Win) window_handle() / RawWindowHandle::Win32 取不到 → 静默 return false 各补一条 warn(Win32 show 失败最可能的暗点)
coordinator.rs emit_capsule get_webview_window("capsule") None → 静默 return 一次性 warn(暗点 A0),AtomicBool 门避免 ~30Hz 刷屏
lib.rs position_capsule_bottom_center(Win) .max(mon.top),无观测 显示器几何 + 最终落点 debug log(证伪「定位到屏幕外」)
Capsule.tsx 收到第一个 capsule:state 事件时一次性 console.info(区分「后端没 emit」vs「emit 了但没渲染/显示」)

验证

  • 本机 cargo check(跨平台部分)+ tsc --noEmit 通过
  • ⚠️ Windows-cfg 部分本机无法交叉编译(ring 的 C 代码需 MSVC),依赖 Windows CI。已逐行核对:no_activate 两处仅含字符串字面量;几何 log 的 10 个占位符对 10 个作用域内参数。

拿到真机含 [capsule] 的日志后,再据 A/B/C/A0 单独开修复 PR。

@claude 请审核(重点:一次性门是否正确、format 占位符/参数是否匹配、是否真的零行为改动)。


PR Type

Other


Description

  • Add one-time warning logs when capsule window handle retrieval fails

  • Add debug log for capsule positioning coordinates on Windows

  • Add console.info on first capsule:state event in webview for frontend diagnostics


Diagram Walkthrough

flowchart LR
  A["Win32 show failed"] -- "log warn" --> B["Capsule window handle missing"]
  C["Capsule webview not found"] -- "log warn" --> D["emit_capsule skipped"]
  E["Position calculated"] -- "log debug" --> F["Monitor geometry + clamped_y"]
  G["Capsule:state received"] -- "console.info" --> H["First event in webview"]
Loading

File Walkthrough

Relevant files
Diagnostic logging
coordinator.rs
Add capsule handle missing warnings                                           

openless-all/app/src-tauri/src/coordinator.rs

  • Added one-time warning logs when window_handle() or
    RawWindowHandle::Win32 fails in show_capsule_window_no_activate
  • Added one-time warning log when capsule webview window is not found
    during emit_capsule
+14/-0   
lib.rs
Add capsule position debug log                                                     

openless-all/app/src-tauri/src/lib.rs

  • Added a debug log for capsule positioning coordinates and monitor
    bounds on Windows
+9/-1     
Capsule.tsx
Add first capsule event log                                                           

openless-all/app/src/components/Capsule.tsx

  • Added a one-time console.info log on the first capsule:state event
    received in the webview
+9/-0     

#470「Windows 语音输入看不到录音胶囊」根因仍未定(PR #471 已明说只加诊断、需真机
日志;byte92 报 macOS 也复现,疑跨平台)。本 PR 不改任何 show/hide/position 行为,
仅在几个静默路径补日志,把根因收敛到 A/B/C 单一分支,帮助拿日志定位:

- coordinator.rs show_capsule_window_no_activate(Windows):两处 window_handle() /
  RawWindowHandle::Win32 取不到时此前静默 return false,补 warn(Win32 show 失败最可能的暗点)。
- coordinator.rs emit_capsule:get_webview_window("capsule") 取不到时此前静默 return,
  补一次性 warn(暗点 A0:窗口压根没创建/已销毁)。沿用 AtomicBool 一次性门,避免 ~30Hz 刷屏。
- lib.rs position_capsule_bottom_center(Windows):定位只夹了上边(.max(mon.top)),
  多显示器/负坐标/异常 DPI 下可能算到屏幕外却无观测,补显示器几何 + 最终落点 debug log。
- Capsule.tsx:webview 收到第一个 capsule:state 事件时打一次 console.info,区分
  「后端没 emit」与「emit 了但窗口没显示/没渲染」。

注:Windows-cfg 部分本机无法交叉编译验证(ring 的 C 代码需 MSVC),依赖 Windows CI。
@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented Jun 4, 2026

@claude 请审核这个零行为诊断 PR(#470 诊断 v2)。重点:(1) 三处 Windows-cfg log(no_activate 两处 warn、lib.rs 几何 debug)的 format 占位符与参数数量/类型是否匹配(本机无法交叉编译验证);(2) CAPSULE_WINDOW_MISSING_LOGGED 一次性门是否正确、是否会在 ~30Hz 音频回调线程刷屏;(3) 前端 capsuleStateFirstLogged 模块级一次性门是否合理;(4) 确认确实未改任何 show/hide/position 行为。

@claude
Copy link
Copy Markdown

claude Bot commented Jun 4, 2026

Claude finished @appergb's task in 3m 13s —— View job


审核 PR #593#470 诊断 v2

  • 读取变更文件
  • 验证 format 占位符与参数
  • 分析 CAPSULE_WINDOW_MISSING_LOGGED 一次性门
  • 分析前端 capsuleStateFirstLogged 门
  • 确认零行为改动
  • 撰写审核报告

(1) Format 占位符 / 参数校验 ✅

coordinator.rsshow_capsule_window_no_activate 两处 warn!

两条均为纯字符串字面量,零占位符、零参数,不存在不匹配风险:

log::warn!("[capsule] no_activate failed: window_handle() unavailable — Win32 show skipped");
log::warn!("[capsule] no_activate failed: non-Win32 RawWindowHandle — Win32 show skipped");

lib.rsposition_capsule_bottom_center 几何 debug!

占位符(格式串) 对应参数 类型
{} {} (mon=...) mon.left, mon.top i32
{} {} (..end) mon.right, mon.bottom i32
{:.2} scale f64
{} {} (size=) phys_w, phys_h i32 (.round() as i32)
{} x i32
{} y i32
{} clamped_y i32

10 个占位符 = 10 个参数,类型全部匹配,{:.2}f64 合法。✅


(2) CAPSULE_WINDOW_MISSING_LOGGED 一次性门 ✅ — 但有一处同 PR 内部不一致⚠️

门本身正确。 AtomicBool::swap(true, Ordering::SeqCst) 与文件内既有三处门(CAPSULE_NO_ACTIVATE_FALLBACK_WARNEDCAPSULE_SUPPRESSED_BY_TOGGLE_LOGGEDCAPSULE_FIRST_SHOW_LOGGED)完全一致。

线程安全 ✅ — 此门在 run_on_main_thread 闭包 内部(主线程)执行,不在音频回调线程上。音频线程只做 app.run_on_main_thread(...) 入队,swap 本身已是原子操作,即使多个闭包排队也只有第一个通过。不会 ~30 Hz 刷屏。

⚠️ 问题:同 PR 里的两处 no_activate warn! 没有类似的门

show_capsule_window_no_activate 也在 run_on_main_thread 的调用链内(emit_capsule → 主线程闭包 → show_capsule_window_for_recordingshow_capsule_window_no_activate)。若 window_handle() 持续返回 Err(例如整个录音会话 HWND 都不可用),这两条 warn! 将以 ~30 Hz 频率持续打印:

// 这两条无速率限制
log::warn!("[capsule] no_activate failed: window_handle() unavailable — Win32 show skipped");
log::warn!("[capsule] no_activate failed: non-Win32 RawWindowHandle — Win32 show skipped");

外层 CAPSULE_NO_ACTIVATE_FALLBACK_WARNED(line 128)只门住 "falling back to window.show()" 那条日志,不压制这两条内层 warn。

建议修复:补一个共享的一次性门,与其他几处保持一致风格:Fix this →

// 建议在 line ~100 加:
static CAPSULE_NO_ACTIVATE_HWND_WARNED: AtomicBool = AtomicBool::new(false);

// 然后包住两条 warn:
let Ok(handle) = window.window_handle() else {
    if !CAPSULE_NO_ACTIVATE_HWND_WARNED.swap(true, Ordering::SeqCst) {
        log::warn!("[capsule] no_activate failed: window_handle() unavailable — Win32 show skipped");
    }
    return false;
};
let RawWindowHandle::Win32(raw) = handle.as_raw() else {
    if !CAPSULE_NO_ACTIVATE_HWND_WARNED.swap(true, Ordering::SeqCst) {
        log::warn!("[capsule] no_activate failed: non-Win32 RawWindowHandle — Win32 show skipped");
    }
    return false;
};

(3) 前端 capsuleStateFirstLogged 模块级门 ✅

let capsuleStateFirstLogged = false;
// ...
if (!capsuleStateFirstLogged) {
  capsuleStateFirstLogged = true;
  console.info('[capsule] first capsule:state received in webview, state=', p.state);
}

合理。 ES 模块是 webview 生命周期内的单例,let 模块变量是正确的一次性门实现。JavaScript 单线程,无竞态。相比 React useRefuseState,模块变量更简单,也不会因组件 unmount/remount(含 React StrictMode 开发期双调用)而重置——对诊断目的(「确认 webview 至少收到过一次事件」)语义正确。

唯一的边缘情况:若 Capsule 组件先被 unmount、等窗口重建后再 mount,后续第一次收到事件不会再打 log。但此场景极少见,且对诊断 #470 不关键。可接受。✅


(4) 零行为改动确认 ✅

文件 原行为 新行为
coordinator.rs show_capsule_window_no_activate return false 新增 warn! return false,控制流不变
coordinator.rs emit_capsule return (get_webview_window None) AtomicBool 门内打 log,return 不变
lib.rs position_capsule_bottom_center set_position(x, y.max(mon.top)) clamped_y = y.max(mon.top)(等价),仅新增 debug!set_position 参数不变
Capsule.tsx setState 等调用无条件执行 console.info 条件分支不影响 setState/setLevel/setMessage,均在 if 块之外执行

确认:无任何 show/hide/position 行为改动。


总结

可以合并,有一处建议修复(非阻塞但推荐):

  • show_capsule_window_no_activate 内两条 warn! 缺一次性门,与 PR 中 CAPSULE_WINDOW_MISSING_LOGGED 的设计意图不一致,若 HWND 持续不可用会产生 ~30 Hz 日志。建议补 CAPSULE_NO_ACTIVATE_HWND_WARNED 门后再合。

其余三个审核点(format 串、CAPSULE_WINDOW_MISSING_LOGGED 门、前端门)全部正确,零行为改动确认无误。

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ❌

471 - Not compliant

Non-compliant requirements:

470 - Not compliant

Non-compliant requirements:

  • 语音输入时显示录音胶囊(修复bug): Not fixed, only diagnostic logs added.
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@H-Chris233 H-Chris233 merged commit a86af40 into beta Jun 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants